/*
 * Middleware
 * Copyright (C) 2010/11
 * Riccardo Pulvirenti, Giuseppe Ravidà, Andrea Tino
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANDABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses
 */

/*!
 * File: core.hpp
 */

#ifndef _CORE_HPP_
#define _CORE_HPP_

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <boost/thread/mutex.hpp>

#include "core_exception.hpp"
#include "worker_descriptor.hpp"
#include "common_types.hpp"

//-----------------------------------------------------------------------------
// Constants
namespace middleware {
/*!
 * Default configuration file name.
 */
const std::string kConfigFileName = "core.config";
/*!
 * Default separator for configuration file: TAGNAME+Separator+TAGVALUE.
 */
const std::string kConfigFileDelimiter = ":";
/*!
 * When an element is not found in the configuration file, this value is
 * returned. Attention: comparisons are made basing on this parameter in order
 * to check whether a parameter was found or not.
 */
const std::string kParameterNotFound = "";
}
//-----------------------------------------------------------------------------
// Configuration parameters
namespace middleware {
/*!
 * Output etiquette.
 */
const std::string kCOREEtq = "CORE:      ";
/*!
 * Represents the type used for a configuration parameter in a configuration
 * file.
 */
typedef const std::string ConfigParam;
/*!
 * Represents the type of value returned when querying for a particular
 * configuration parameter's value.
 */
typedef const std::string ConfigValue;
/*!
 * Ip v4 address of the current peer.
 */
ConfigParam kCPAddrBindIp = "CONFIG_ADDRME_IP";
/*!
 * TCP Port of Manager of the current peer in order to listen for incoming
 * TaskDescriptor.
 */
ConfigParam kCPAddrManBindPort = "CONFIG_ADDRME_MAN_PORT";
/*!
 * TCP Port of Discovery of the current peer in order to listen for incoming
 * WorkerDescriptor.
 */
ConfigParam kCPAddrDiscBindPort = "CONFIG_ADDRME_DISC_PORT";
/*!
 * TCP Port of Worker of the current peer in order to listen for incoming
 * Data from other peers when routing executable tasks.
 */
ConfigParam kCPAddrWBindPort = "CONFIG_ADDRME_W_PORT";
/*!
 * Number of initial known peers defined in the configuration file; this is
 * the number of provided peers that the current peer, when running, will
 * automatically recognize as initial knowledge.
 */
ConfigParam kCPOtherPeersNum = "CONFIG_OTHERPEERS_NUM";
/*!
 * Prefix for Ip address configuration parameter specifying Ip address of
 * known peer. Example: CONFIG_ADDRPEER_1_IP, CONFIG_ADDRPEER_2_IP.
 */
ConfigParam kCPAddrPeerXIpPre = "CONFIG_ADDRPEER_";
/*!
 * Postfix for Ip address configuration parameter specifying Ip address of
 * known peer. Example: CONFIG_ADDRPEER_1_IP, CONFIG_ADDRPEER_2_IP.
 */
ConfigParam kCPAddrPeerXIpPost = "_IP";
/*!
 * Prefix for Port number configuration parameter specifying Port number of
 * Manager's known peer. Example: CONFIG_ADDRPEER_1_TASKS_PORT,
 * CONFIG_ADDRPEER_2_TASKS_PORT.
 */
ConfigParam kCPAddrPeerXTaskDescsPortPre = "CONFIG_ADDRPEER_";
/*!
 * Postfix for Port number configuration parameter specifying Port number of
 * Manager's known peer. Example: CONFIG_ADDRPEER_1_TASKS_PORT,
 * CONFIG_ADDRPEER_2_TASKS_PORT.
 */
ConfigParam kCPAddrPeerXTaskDescsPortPost = "_TASKS_PORT";
/*!
 * Prefix for Port number configuration parameter specifying Port number of
 * WorkerDiscovery's known peer. Example: CONFIG_ADDRPEER_1_WRKRS_PORT,
 * CONFIG_ADDRPEER_2_WRKRS_PORT.
 */
ConfigParam kCPAddrPeerXWorkerDescsPortPre = "CONFIG_ADDRPEER_";
/*!
 * Postfix for Port number configuration parameter specifying Port number of
 * WorkerDiscovery's known peer. Example: CONFIG_ADDRPEER_1_WRKRS_PORT,
 * CONFIG_ADDRPEER_2_WRKRS_PORT.
 */
ConfigParam kCPAddrPeerXWorkerDescsPortPost = "_WRKRS_PORT";
/*!
 * Prefix for Port number configuration parameter specifying Port number of
 * Worker's known peer. Example: CONFIG_ADDRPEER_1_DATA_PORT,
 * CONFIG_ADDRPEER_2_DATA_PORT.
 */
ConfigParam kCPAddrPeerXDataPortPre = "CONFIG_ADDRPEER_";
/*!
 * Postfix for Port number configuration parameter specifying Port number of
 * Worker's known peer. Example: CONFIG_ADDRPEER_1_DATA_PORT,
 * CONFIG_ADDRPEER_2_DATA_PORT.
 */
ConfigParam kCPAddrPeerXDataPortPost = "_DATA_PORT";
/*!
 * Worker capability for current peer. Represents the number of CPUs the
 * machine is equiped with.
 */
ConfigParam kCPWorkerCapabP = "CONFIG_WORKERCAPAB_P";
/*!
 * Worker capability for current peer. Represents the number of cores per
 * CPU the architecture's machine is equiped with.
 */
ConfigParam kCPWorkerCapabC = "CONFIG_WORKERCAPAB_C";
/*!
 * Worker capability for current peer. Represents bandwidth available to
 * reach the current machine. Band is expressed in Kbits.
 */
ConfigParam kCPWorkerCapabB = "CONFIG_WORKERCAPAB_B";
/*!
 * Worker capability for current peer. Represents the CPU's clock frequency of
 * the machine. Frequency is expressed in MHz.
 */
ConfigParam kCPWorkerCapabZ = "CONFIG_WORKERCAPAB_Z";
/*!
 * Worker capability for current peer. Represents the network distance from
 * the current peer to all the other peers. A simplifying assumption is
 * considered: all peers have a general distance one from each other; this
 * parameter does not measure the precise distance, just a generic one. This
 * parameter measures distance in terms of "router hops" (adimensional number).
 */
ConfigParam kCPWorkerCapabD = "CONFIG_WORKERCAPAB_D";
/*!
 * Worker capability for current peer. Represents the RAM memory capacity of the
 * current peer. This parameter measures memory in MBytes.
 */
ConfigParam kCPWorkerCapabM = "CONFIG_WORKERCAPAB_M";
}
//-----------------------------------------------------------------------------
// Class definitions
namespace middleware {
/*! \class CORE
 * \brief Logic entry point for the application.
 *
 * Defines the entry point of the application. CORE provides services to grab
 * configuration file and look for parameters. It also configures UI, Manager,
 * WorkerDiscovery and Worker and runs them as four separate threads.
 */
class CORE {
public:
	/*!
	 * Constructor. Initalizes file name to default (kConfigFileName).
	 * Log files postfix are set to random value.
	 */
	CORE();
	/*!
	 * Constructor. Initalizes CORE providing a specific configuration file,
	 * different from the default one, and also specifies which prefix to use
	 * for log files.
	 */
	explicit CORE(const std::string& filename, const std::string& log_postfix);
	/*!
	 * Destructor.
	 */
	~CORE();
	/*!
	 * \brief Causes the class to run the main execution flow. A call to this
	 * method will cause CORE to execute its functionalities as an indipendent
	 * component of the application.
	 *
	 * CORE will instantiate UI, Manager, WorkerDiscovery and Worker with
	 * parameters provided in the configuration file. Then all components will
	 * be run. CORE will finally wait for components to end their execution by
	 * joining them.
	 */
	void exec();
	/*!
	 * \brief Provides access to configuration file parameters.
	 *
	 * By calling this operator, it is possible to search for a parameter
	 * and getting its value back. If no param is found, kParameterNotFound
	 * is returned. The function looks for the first occurrence then exits.
	 * \param param_name Name of the parameter to look for in the configuration file.
	 * \return Returns a string representing the parameter's value.
	 * \exception CoreException Invalid configuration file path provided (file not found).
	 */
	std::string operator[](const std::string& param_name) throw(CoreException);
private:
	/*!
	 * Initialization sequence.
	 */
	void bonjour() throw(CoreException);
	/*!
	 * Opens configuration file.
	 */
	void Open(std::ifstream& config_file) throw(CoreException);
	/*!
	 * Closes the file
	 */
	void Close(std::ifstream& config_file);
	/*!
	 * Configuration file name. Path will be local.
	 */
	std::string _config_filename;
	/*!
	 * Logers postfix.
	 */
	std::string _logger_postfix;
	/*!
	 * Maintains the set of worker descriptors used by worker and discovery
	 * to send status and find best worker.
	 */
	PeersSet _peers_worker_descriptors;
	/*!
	 * Mutex for vector of worker descriptor.
	 */
	boost::mutex _peers_worker_descriptors_mutex;
}; /* CORE */
} /* middleware */

#endif
